<template>
  <div class="markdown">
    <div id="vditor" ref="vditor"></div>
    <div class="select-dialog">
      <el-dialog title="库中图片选择或直接粘贴" v-model="isImageSelector" width="1112px" :append-to-body="true">
        <div class="image-list">
          <el-radio-group v-model="selectImagePath">
            <el-radio-button :label="image.url" :key="image.id" v-for="(image) in imageList">
              <el-image fit="cover" :src="constant.imageUrl  +image.url"/>
            </el-radio-button>
          </el-radio-group>
        </div>
        <div class="image-list-page">
          <el-pagination
              :hide-on-single-page="true"
              background
              @current-change="handleCurrentChange"
              :page-size="imagePage.pageSize"
              layout="total,prev, pager, next"
              :total="imagePage.totalCount">
          </el-pagination>
        </div>
        <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="onImageSelector" @keyup.enter="onImageSelector">确 定</el-button>
           <el-button @click="clearImageSelect">取 消</el-button>
          </span>
      </el-dialog>
    </div>
    <div class="link-dialog">
      <el-dialog title="插入链接" v-model="linkShow" width="1112px" :append-to-body="true">
        <el-form :model="link" label-width="120px">
          <el-form-item label="链接名称">
            <el-input v-model="link.name"/>
          </el-form-item>
          <el-form-item label="链接地址" required>
            <el-radio-group v-model="link.isOwn">
              <el-radio :label="0">https://</el-radio>
              <el-radio :label="1">http://</el-radio>
              <el-radio :label="2">ftp://</el-radio>
              <el-radio :label="3">自定义</el-radio>
            </el-radio-group>
            <el-input v-if="link.isOwn===0" v-model="link.url">
              <template #prepend>https://</template>
            </el-input>
            <el-input v-else-if="link.isOwn===1" v-model="link.url">
              <template #prepend>http://</template>
            </el-input>
            <el-input v-else-if="link.isOwn===2" v-model="link.url">
              <template #prepend>ftp://</template>
            </el-input>
            <el-input v-else v-model="link.url"/>
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="onLink">确 定</el-button>
           <el-button @click="linkShow = false">取 消</el-button>
          </span>
      </el-dialog>
    </div>
  </div>
</template>

<script>
//npm install vditor --save
import Vditor from "vditor";
import "vditor/dist/index.css";
import {successCode} from "@/api/httpApi/base/http.js";
import {emoji_small} from './icon/emoji2.js'
import {emoji_animal} from './icon/emoji1.js'
import {constantStore} from "@/stores/constantStore.js";
import {defineModel} from "vue";

export default {
  emits: ['update'],
  props: {
    show: {//是否创建Markdown
      type: Boolean,
      default: true
    },
    modelValue: String,
    placeholder: {
      type: String,
      default: "编辑文章，支持MarkDown格式...."
    },
    height: {
      type: Number,
      default: ''
    },
    minHeight: {
      type: Number,
      default: 200
    },
    width: {
      type: Number,
    },
    lang: { //语言 ['zh_CN', 'zh_TW', 'en_US', 'fr_FR', 'ja_JP', 'ko_KR', 'ru_RU', 'sv_SE']
      type: Number,
      default: 0
    },
    theme: {
      type: String,
      default: "classic"
    },
    toolBarHide: {
      type: Boolean,
      default: false
    },
    mode: {
      type: String,
      default: "ir", //"wysiwyg" | "sv" | "ir"
    },
    clickSave: {
      type: Function,
    },
    outline: {
      type: Boolean,
      default: false
    }
  },
  components: {},
  data() {
    return {
      imagePostUrl: '/_api/portal/image',
      constant: constantStore(),
      vditorMarkDown: "",
      linkShow: false,
      link: {
        prefix: "",
        name: "",
        url: "",
        isOwn: 0,
      },
      selectImagePath: "",
      imageList: [],
      imagePage: {
        currentPage: 1,
        totalPage: -1,
        pageSize: 15,
        totalCount: -1,
      },
      isImageSelector: false,
      imageSelectLoading: false,
      langs: ['zh_CN', 'zh_TW', 'en_US', 'fr_FR', 'ja_JP', 'ko_KR', 'ru_RU', 'sv_SE'],
    }
  },
  mounted() {
    if (this.show) {
      this.initMarkDown();
    }
  },
  watch: {
    show(newVal) {
      if (newVal) {
        this.initMarkDown();
      } else {
        if (this.vditorMarkDown !== '') {
          this.vditorMarkDown.destroy()
        }
      }
    }
  },
  methods: {
    initMarkDown() {
      let that = this;
      this.vditorMarkDown = new Vditor('vditor', {
        height: that.height,
        minHeight: that.minHeight,
        width: that.width === '' ? '100%' : that.width,
        lang: that.langs[that.lang],
        placeholder: that.placeholder,
        /** 主题。默认值: 'classic' */
        theme: that.theme,
        value: that.text,
        mode: that.mode,
        hide: false,
        i18n: null,
        input(val) {
          let newVal = val.replace(/^\s+|\s+$/g, '');
          that.$emit("update", newVal);
          that.seePoint(true, document.querySelector('.bar-save .point'));
        },
        esc(val) {

        },
        counter: {
          enable: true,
          type: 'markdown'
        },
        preview: {
          markdown: {
            toc: true,
            mark: true,
            autoSpace: true,
            fixTermTypo: true,
            footnotes: true,
            listStyle: true,
          },
          delay: 1,
          hljs: {
            style: 'catppuccin-frappe',
            lineNumber: true,
            enable: true
          },
          math: {
            inlineDigit: true,
            math: {
              engine: 'KaTeX',
            },
          },
        },
        outline: {
          /** 初始化是否展现大纲。默认值: false */
          enable: that.outline,
          /** 大纲位置：'left', 'right'。默认值: 'left' */
          position: 'left'
        },
        fullscreen: {
          index: 999 //层级 z-index相当于
        },
        hint: {//表情包
          /** 默认表情，可从 [lute/emoji_map](https://github.com/88250/lute/blob/master/parse/emoji_map.go#L32) 中选取，也可自定义 */
          emoji: [...emoji_small, ...emoji_animal],
          /** 表情图片地址。默认值: 'https://unpkg.com/vditor@${VDITOR_VERSION}/dist/images/emoji' */
          emojiPath: 'https://unpkg.com/vditor@${VDITOR_VERSION}/dist/images/emoji',
          /** 提示内容是否进行 md 解析 */
          parse: false,
          /** 常用表情提示 HTML */
          emojiTail: "",
          /** 提示 debounce 毫秒间隔。默认值: 200 */
          delay: 200,
          extend: [
            {
              key: '@',
              hint: (key) => {//特殊字符检测
                if ('vanessa'.indexOf(key.toLocaleLowerCase()) > -1) {
                  return [
                    {
                      value: '@一款编辑器',
                      html: '一款编辑器',
                    }]
                }
                return []
              },
            },
            {}],
        },
        resize: {
          /** 是否支持大小拖拽。默认值: false */
          enable: false,
          /** 拖拽栏位置：'top', 'bottom'。默认值: bottom */
          position: 'bottom',
          /** 拖拽结束的回调。默认值:  */
          after(height) {
          }
        },
        tab: '\t',
        typewriterMode: true,
        toolbarConfig: {
          pin: true,
          hide: that.toolBarHide,
          redo: true, // 显示重做按钮
          undo: true // 显示撤销按钮
        },
        cache: {
          // id:"markdown_text",
          // enable: true,
          enable: false
        },
        toolbar: [
          {
            name: 'outline',
            tip: "目录"
          },
          {
            name: 'emoji',

          },
          'headings', //标题
          'bold',//粗体
          'italic', // 斜体
          'strike',//删除线
          'devtools',
          'br',//删除线
          '|',
          'list',//无序
          'ordered-list',//有序
          'check',//任务列表
          'outdent',//反向缩进
          'indent',//列表缩进
          '|',
          'quote',//引用
          'line',//分割线
          'code',//代码
          'inline-code',//行内代码
          'insert-before',//起始插入行
          'insert-after',//末尾插入行
          '|',
          'record', //录音
          'table',//表格
          {
            /** 唯一标示 */
            name: 'my-link',
            /** svg 图标 HTML */
            icon: "<svg class='icon' aria-hidden='true'><use xlink:href='#icon-youqinglianjie'></use></svg>",
            /** 元素的样式名称 */
            className: "",
            /** 提示 */
            tip: '插入链接',
            /** 快捷键，支持⌘/ctrl-key 或 ⌘/ctrl-⇧/shift-key 格式的配置，不支持 wysiwyg 模式 */
            hotkey: '',
            /** 插入编辑器中的后缀 */
            suffix: "",
            /** 插入编辑器中的前缀 */
            prefix: "",
            /** 提示位置：ne, nw */
            tipPosition: 'ne',
            /** 子菜单 */
            toolbar: [],
            /** 菜单层级，最大为 3，内部使用 */
            // level: ,
            click(event, vditor) {
              that.link.name = '';
              that.link.url = '';
              that.linkShow = true;
            }
          },
          // {
          //   name: 'image',////图片（Image）
          //   tip: '添加已有图片',
          //   tipPosition: 'ne',
          //   icon: '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-tupian"></use></svg>',
          //   click(event, vditor) {
          //     that.getImageList();
          //     that.isImageSelector = true;
          //   }
          // },
          'upload',//上传（Upload）
          '|',
          'undo',//撤销
          'redo',//重做
          {
            name: 'save',////图片（Image）
            tip: '保存',
            tipPosition: 'ne',
            className: 'bar-save',
            icon: '<i class="point"></i>' +
                '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-baocun"></use></svg>',
            click(event, vditor) {
              that.clickSave();
              that.seePoint(false, document.querySelector('.bar-save .point'));
            }
          },
          '|',
          'fullscreen',//全屏（Full Screen）
          'both',//实时预览（Realtime Preview）
          'preview',//预览（Preview）
          '|',
          'edit-mode', //编辑模式
          'content-theme',//内容主题
          'code-theme',//代码主题
          'export',//导出
          // '|',
          // {
          //   name: 'more',
          //   toolbar: [],
          // }
        ],
        upload: {
          // accept: 'image/*,.mp3, .wav, .rar',
          accept: 'image/*',
          url: that.imagePostUrl,//文件上传
          fieldName: "file",
          linkToImgUrl: '/admin/image/article_content',//图片上传
          filename(name) {
            return name.replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, '').replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').replace('/\\s/g', '')
          },
          success(e, res) {
            that.setPastePic(JSON.parse(res));
          },
          linkToImgCallback(res) {
            that.setPastePic(JSON.parse(res));
          },
          error() {
            that.$message.error("图片上传失败，请联系管理员");
          }
        },
      });
    },
    setPastePic(res) {
      if (res.code === successCode) {
        this.vditorMarkDown.insertValue(`![](${this.constant.imageUrl + res.data})`);
      } else {
        this.$message.error(res.message);
      }
    },
    handleCurrentChange() {
      this.imagePage.currentPage++;
      this.getImageList();
    },
    getImageList() {
      this.imageSelectLoading = true;
      listImages(this.imagePage.currentPage, this.imagePage.pageSize, '').then(res => {
        if (res.code === successCode) {
          this.imageList = res.data.contents;
          this.imagePage.currentPage = res.data.currentPage;
          this.imagePage.totalPage = res.data.totalPage;
          this.imagePage.totalCount = res.data.totalCount;
        } else {
          this.$message.error(res.message);
        }
        this.imageSelectLoading = false;
      })
    },
    clearImageSelect() {
      this.isImageSelector = false;
      this.selectImagePath = '';
    },
    onImageSelector() {
      this.isImageSelector = false;
      this.vditorMarkDown.insertValue(`![](${this.constant.imageUrl + this.selectImagePath})`);
    },
    seePoint(bool, seePointDom) {
      if (bool) {
        seePointDom.style.display = 'block';
      } else {
        seePointDom.style.display = 'none';
      }
    },
    onLink() {
      if (this.link.url.trim() === '') {
        this.$message.error("链接不能为空");
        return;
      }
      if (this.link.isOwn === 0) {
        this.link.prefix = 'https://';
      } else if (this.link.isOwn === 1) {
        this.link.prefix = 'http://';
      } else if (this.link.isOwn === 2) {
        this.link.prefix = 'ftp://';
      } else {
        this.link.prefix = '';
      }
      this.linkShow = false;
      this.vditorMarkDown.insertValue(`[${this.link.name}](${this.link.prefix + this.link.url})`);
    },
  }
}
</script>
<style scoped>
.markdown {
  --font-size: 2rem;
  --icon-right: 1.5rem;
  --point-size: 0.4rem;
}


:deep(.vditor-toolbar) {
  padding: 0.5rem 1rem !important;
  padding-right: 0 !important;
}

:deep(.link-dialog .el-dialog) {
  width: 60rem;
}

:deep(.link-dialog .el-dialog__header) {
  margin: auto;
}

:deep(.bar-save .point) {
  display: none;
  position: absolute;
  top: 5px;
  left: 2rem;
  width: var(--point-size);
  height: var(--point-size);
  border-radius: 50%;
  border: #d50c0c solid var(--point-size);
}

:deep(.vditor-preview__action > button > svg) {
  width: var(--font-size) !important;
  height: var(--font-size) !important;
}

:deep(.vditor-preview__action > button) {
  font-size: var(--font-size);
}

:deep(.vditor-toolbar__item) {
  margin-right: var(--icon-right);
}

:deep(.vditor-toolbar__item svg) {
  width: var(--font-size) !important;
  height: var(--font-size) !important;
}

.select-dialog .image-list-page {
  margin-top: 1rem;
  margin-bottom: 1rem;
}

:deep(.select-dialog .image-action) {
  padding-bottom: 1rem;
  margin-bottom: 0.5rem;
}

:deep(.select-dialog .el-radio-button .el-radio-button__inner),
:deep(.select-dialog .el-radio-button:first-child .el-radio-button__inner),
:deep(.select-dialog .el-radio-button:last-child .el-radio-button__inner) {
  border: none;
  padding: 3px;
  margin: 5px 5px;
  border-radius: 4px;
}

:deep(.select-dialog .el-radio-button:nth-child(5n+1) .el-radio-button__inner) {
  margin-left: 0;
}

:deep(.select-dialog .el-radio-button:nth-child(5n+5) .el-radio-button__inner) {
  margin-right: 0px;
}

:deep(.select-dialog .image-list img) {
  width: 200px;
  height: 100px;
}

.dialog-footer {
  margin-top: 1rem;
}
</style>
